package config

import (
	"context"
	"encoding/json"
	"fmt"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"io"
	"log"
	"net/http"
)

var DbInstanceMap = map[int]*ConnetInfo{}
var dbIndexer = 0

type ConnetInfo struct {
	DbType  string
	Conn    *gorm.DB
	DbId    int
	Connect *IDbConnect
}

func (conf *ConnetInfo) PutInGlobal(connect *IDbConnect) int {
	dbIndexer++
	var index = dbIndexer
	conf.DbId = index
	conf.Connect = connect
	DbInstanceMap[index] = conf
	return index
}

type IDbConnect interface {
	Connect() bool
	ShowTables() []TableInfo
	ShowDatabase() []string
	DbInfo() *DbConfig
	ExecuteSql(sql string) error
}

type MongodbDbConnect struct {
	*DbConfig
}

func (conf *MongodbDbConnect) Connect() bool {
	// MongoDB连接URI
	uri := fmt.Sprintf("mongodb://%s:%s@%s:%d/%s",
		conf.Username,
		conf.Password,
		conf.Host,
		conf.Port,
		conf.DbName)

	// 设置连接选项
	clientOptions := options.Client().ApplyURI(uri)

	// 建立连接
	client, err := mongo.Connect(context.TODO(), clientOptions)
	if err != nil {
		fmt.Println("Failed to connect to MongoDB:", err)
		return false
	}

	// 检查连接
	err = client.Ping(context.TODO(), nil)
	if err != nil {
		fmt.Println("Failed to ping MongoDB:", err)
		return false
	}

	// 存储连接信息
	var sss = &ConnetInfo{
		DbType: conf.DbType,
		Conn:   nil, // MongoDB不使用gorm
	}
	var ccq IDbConnect = conf
	var ind = sss.PutInGlobal(&ccq)
	conf.DbId = ind

	return true
}
func (conf *MongodbDbConnect) ShowTables() []TableInfo {
	return nil
}
func (conf *MongodbDbConnect) ShowDatabase() []string {
	return nil
}
func (conf *MongodbDbConnect) DbInfo() *DbConfig {
	return conf.DbConfig
}
func (conf *MongodbDbConnect) ExecuteSql(sql string) error {
	return nil
}

type TableInfo struct {
	TableName       string
	TableCreateDesc string
}

type DbConfig struct {
	DbId     int    `json:"db_id"`
	DbType   string `json:"db_type"`
	Host     string `json:"host"`
	Port     int    `json:"port"`
	Username string `json:"username"`
	Password string `json:"password"`
	Url      string `json:"url"`
	DbName   string `json:"db_name"`
}

func (conf *DbConfig) MakeConnInstance() IDbConnect {
	if conf.DbId != 0 {
		var db = DbInstanceMap[conf.DbId]
		ndb := db.Connect
		return *ndb
	}
	if conf.DbType == "mysql" {
		return &MysqlDbConnect{
			DbConfig: conf,
		}
	}
	if conf.DbType == "sqlite" {
		return &Sqlite3DbConnect{
			DbConfig: conf,
		}
	}
	if conf.DbType == "postgresql" {
		return &PostgresqlDbConnect{
			DbConfig: conf,
		}
	}
	if conf.DbType == "mongodb" {
		return &MongodbDbConnect{
			DbConfig: conf,
		}
	}
	return nil
}

type DbConfigFactory struct {
	R *http.Request
}

func (d *DbConfigFactory) MakeConfig() DbConfig {
	var bytes, _ = io.ReadAll(d.R.Body)
	var s = string(bytes)
	var dbC = DbConfig{}
	err := json.Unmarshal([]byte(s), &dbC)
	if err != nil {
		return DbConfig{}
	}
	return dbC
}

type MysqlDbConnect struct {
	*DbConfig
}

type PostgresqlDbConnect struct {
	*DbConfig
}

func (conf *PostgresqlDbConnect) Connect() bool {
	dsn := fmt.Sprintf(
		"host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Shanghai",
		conf.Host,
		conf.Username,
		conf.Password,
		conf.DbName,
		conf.Port,
	)
	_, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("Failed to connect to database:", err)
		return false
	}
	return true
}
func (conf *PostgresqlDbConnect) ShowTables() []TableInfo {
	var db = DbInstanceMap[conf.DbId]
	//查询所有postgresql表名
	var tables []string
	db.Conn.Raw("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'").Scan(&tables)
	var tabs []TableInfo
	// 打印所有表名
	for _, table := range tables {
		fmt.Println(table)
		//查询表名对应的建表语句
		var createTableSql string
		db.Conn.Raw("SELECT pg_get_viewdef('" + table + "')").Scan(&createTableSql)
		fmt.Println(createTableSql)
		tabs = append(tabs, TableInfo{
			TableName:       table,
			TableCreateDesc: createTableSql,
		})
	}

	return tabs
}

func (conf *PostgresqlDbConnect) ExecuteSql(sql string) error {
	var db = DbInstanceMap[conf.DbId]
	var result = db.Conn.Exec(sql)
	return result.Error
}

func (conf *PostgresqlDbConnect) ShowDatabase() []string {
	return []string{"show databases"}
}
func (conf *PostgresqlDbConnect) DbInfo() *DbConfig {
	return conf.DbConfig
}

func (conf *MysqlDbConnect) Connect() bool {
	var info = conf.DbInfo()
	dsn := fmt.Sprintf(
		"%s:%s@tcp(%s:%d)/mysql?charset=utf8mb4&parseTime=True&loc=Local",
		info.Username,
		info.Password,
		info.Host,
		info.Port,
	)

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("Failed to connect to database:", err)
		return false
	}
	var sss = &ConnetInfo{
		DbType: info.DbType,
		Conn:   db,
	}
	var ccq IDbConnect = conf
	var ind = sss.PutInGlobal(&ccq)
	info.DbId = ind
	return true
}
func (conf *MysqlDbConnect) ExecuteSql(sql string) error {
	var db = DbInstanceMap[conf.DbId]
	var result = db.Conn.Exec(sql)
	return result.Error
}

func (conf *MysqlDbConnect) ShowTables() []TableInfo {
	var db = DbInstanceMap[conf.DbId]
	//查询所有表名
	var tables []string
	db.Conn.Raw("SHOW TABLES").Scan(&tables)
	// 打印所有表名
	var tabs []TableInfo
	for _, table := range tables {
		fmt.Println(table)
		// 查询表名对应的建表语句
		type TableCreateInfo struct {
			TableName       string `gorm:"column:Table"`
			TableCreateDesc string `gorm:"column:Create Table"`
		}
		var tableCreateInfo TableCreateInfo
		result := db.Conn.Raw("SHOW CREATE TABLE " + table).Scan(&tableCreateInfo)
		if result.Error != nil {
			fmt.Printf("Failed to query create table statement for %s: %v\n", table, result.Error)
			continue
		}
		if result.RowsAffected == 0 {
			fmt.Printf("No create table statement found for %s\n", table)
			continue
		}
		tabs = append(tabs, TableInfo{
			TableName:       table,
			TableCreateDesc: tableCreateInfo.TableCreateDesc,
		})
	}
	return tabs
}

func (conf *MysqlDbConnect) ShowDatabase() []string {
	//mysql 查询所有数据库名
	var db = DbInstanceMap[conf.DbId]
	var databases []string
	// 执行 SHOW DATABASES 语句
	db.Conn.Raw("SHOW DATABASES").Scan(&databases)

	// 打印所有数据库名
	fmt.Println("所有逻辑数据库:")
	for _, dbName := range databases {
		fmt.Println(dbName)
	}
	return databases
}
func (conf *MysqlDbConnect) DbInfo() *DbConfig {
	return conf.DbConfig
}

type Sqlite3DbConnect struct {
	*DbConfig
}

func (conf *Sqlite3DbConnect) ExecuteSql(sql string) error {
	var db = DbInstanceMap[conf.DbId]
	var result = db.Conn.Exec(sql)
	return result.Error
}

func (conf *Sqlite3DbConnect) Connect() bool {
	var info = conf.DbInfo()
	db, err := gorm.Open(sqlite.Open(info.Url), &gorm.Config{})
	if err != nil {
		fmt.Println("Failed to connect to database:", err)
		return false
	}

	var sss = &ConnetInfo{
		DbType: info.DbType,
		Conn:   db,
	}
	var ccq IDbConnect = conf
	var ind = sss.PutInGlobal(&ccq)
	info.DbId = ind

	return true
}

func (conf *Sqlite3DbConnect) ShowTables() []TableInfo {
	//sqlite3 查询所有表名
	var db = DbInstanceMap[conf.DbId]

	// 定义一个结构体来存储查询结果
	type Table struct {
		Name string `gorm:"column:name"`
	}

	var tables []Table
	// 查询 sqlite_master 表获取所有表名
	result := db.Conn.Table("sqlite_master").Where("type = ?", "table").Find(&tables)
	if result.Error != nil {
		log.Fatalf("failed to query tables: %v", result.Error)
	}

	var tabs []TableInfo
	// 打印所有表名
	for _, table := range tables {
		//查询表名对应的建表语句
		var createTableSql string
		result := db.Conn.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND name = ?", "table", table.Name).Scan(&createTableSql)
		fmt.Println(result)
		if result.Error != nil {
			log.Fatalf("failed to query table: %v", result.Error)
		}
		fmt.Println(createTableSql)
		fmt.Println(table.Name)
		tabs = append(tabs, TableInfo{
			TableName:       table.Name,
			TableCreateDesc: createTableSql,
		})
	}
	return tabs
}

func (conf *Sqlite3DbConnect) ShowDatabase() []string {
	return []string{"show databases"}
}

func (conf *Sqlite3DbConnect) DbInfo() *DbConfig {
	return conf.DbConfig
}

// 定义一个模型
type User struct {
	gorm.Model
	Name  string
	Email string
}
